home *** CD-ROM | disk | FTP | other *** search
/ Clickx 96 / Clickx 96.iso / software / tools / tool / xbmc-10.1.exe / addons / script.module.pil / lib / PIL / IptcImagePlugin.py < prev    next >
Encoding:
Python Source  |  2009-04-06  |  7.5 KB  |  289 lines

  1. #
  2. # The Python Imaging Library.
  3. # $Id$
  4. #
  5. # IPTC/NAA file handling
  6. #
  7. # history:
  8. # 1995-10-01 fl   Created
  9. # 1998-03-09 fl   Cleaned up and added to PIL
  10. # 2002-06-18 fl   Added getiptcinfo helper
  11. #
  12. # Copyright (c) Secret Labs AB 1997-2002.
  13. # Copyright (c) Fredrik Lundh 1995.
  14. #
  15. # See the README file for information on usage and redistribution.
  16. #
  17.  
  18.  
  19. __version__ = "0.3"
  20.  
  21.  
  22. import Image, ImageFile
  23. import os, tempfile
  24.  
  25.  
  26. COMPRESSION = {
  27.     1: "raw",
  28.     5: "jpeg"
  29. }
  30.  
  31. PAD = chr(0) * 4
  32.  
  33. #
  34. # Helpers
  35.  
  36. def i16(c):
  37.     return ord(c[1]) + (ord(c[0])<<8)
  38.  
  39. def i32(c):
  40.     return ord(c[3]) + (ord(c[2])<<8) + (ord(c[1])<<16) + (ord(c[0])<<24)
  41.  
  42. def i(c):
  43.     return i32((PAD + c)[-4:])
  44.  
  45. def dump(c):
  46.     for i in c:
  47.         print "%02x" % ord(i),
  48.     print
  49.  
  50. ##
  51. # Image plugin for IPTC/NAA datastreams.  To read IPTC/NAA fields
  52. # from TIFF and JPEG files, use the <b>getiptcinfo</b> function.
  53.  
  54. class IptcImageFile(ImageFile.ImageFile):
  55.  
  56.     format = "IPTC"
  57.     format_description = "IPTC/NAA"
  58.  
  59.     def getint(self, key):
  60.         return i(self.info[key])
  61.  
  62.     def field(self):
  63.         #
  64.         # get a IPTC field header
  65.         s = self.fp.read(5)
  66.         if not len(s):
  67.             return None, 0
  68.  
  69.         tag = ord(s[1]), ord(s[2])
  70.  
  71.         # syntax
  72.         if ord(s[0]) != 0x1C or tag[0] < 1 or tag[0] > 9:
  73.             raise SyntaxError, "invalid IPTC/NAA file"
  74.  
  75.         # field size
  76.         size = ord(s[3])
  77.         if size > 132:
  78.             raise IOError, "illegal field length in IPTC/NAA file"
  79.         elif size == 128:
  80.             size = 0
  81.         elif size > 128:
  82.             size = i(self.fp.read(size-128))
  83.         else:
  84.             size = i16(s[3:])
  85.  
  86.         return tag, size
  87.  
  88.     def _is_raw(self, offset, size):
  89.         #
  90.         # check if the file can be mapped
  91.  
  92.         # DISABLED: the following only slows things down...
  93.         return 0
  94.  
  95.         self.fp.seek(offset)
  96.         t, sz = self.field()
  97.         if sz != size[0]:
  98.             return 0
  99.         y = 1
  100.         while 1:
  101.             self.fp.seek(sz, 1)
  102.             t, s = self.field()
  103.             if t != (8, 10):
  104.                 break
  105.             if s != sz:
  106.                 return 0
  107.             y = y + 1
  108.         return y == size[1]
  109.  
  110.     def _open(self):
  111.  
  112.         # load descriptive fields
  113.         while 1:
  114.             offset = self.fp.tell()
  115.             tag, size = self.field()
  116.             if not tag or tag == (8,10):
  117.                 break
  118.             if size:
  119.                 tagdata = self.fp.read(size)
  120.             else:
  121.                 tagdata = None
  122.             if tag in self.info.keys():
  123.                 if isinstance(self.info[tag], list):
  124.                     self.info[tag].append(tagdata)
  125.                 else:
  126.                     self.info[tag] = [self.info[tag], tagdata]
  127.             else:
  128.                 self.info[tag] = tagdata
  129.  
  130.             # print tag, self.info[tag]
  131.  
  132.         # mode
  133.         layers = ord(self.info[(3,60)][0])
  134.         component = ord(self.info[(3,60)][1])
  135.         if self.info.has_key((3,65)):
  136.             id = ord(self.info[(3,65)][0])-1
  137.         else:
  138.             id = 0
  139.         if layers == 1 and not component:
  140.             self.mode = "L"
  141.         elif layers == 3 and component:
  142.             self.mode = "RGB"[id]
  143.         elif layers == 4 and component:
  144.             self.mode = "CMYK"[id]
  145.  
  146.         # size
  147.         self.size = self.getint((3,20)), self.getint((3,30))
  148.  
  149.         # compression
  150.         try:
  151.             compression = COMPRESSION[self.getint((3,120))]
  152.         except KeyError:
  153.             raise IOError, "Unknown IPTC image compression"
  154.  
  155.         # tile
  156.         if tag == (8,10):
  157.             if compression == "raw" and self._is_raw(offset, self.size):
  158.                 self.tile = [(compression, (offset, size + 5, -1),
  159.                              (0, 0, self.size[0], self.size[1]))]
  160.             else:
  161.                 self.tile = [("iptc", (compression, offset),
  162.                              (0, 0, self.size[0], self.size[1]))]
  163.  
  164.     def load(self):
  165.  
  166.         if len(self.tile) != 1 or self.tile[0][0] != "iptc":
  167.             return ImageFile.ImageFile.load(self)
  168.  
  169.         type, tile, box = self.tile[0]
  170.  
  171.         encoding, offset = tile
  172.  
  173.         self.fp.seek(offset)
  174.  
  175.         # Copy image data to temporary file
  176.         outfile = tempfile.mktemp()
  177.         o = open(outfile, "wb")
  178.         if encoding == "raw":
  179.             # To simplify access to the extracted file,
  180.             # prepend a PPM header
  181.             o.write("P5\n%d %d\n255\n" % self.size)
  182.         while 1:
  183.             type, size = self.field()
  184.             if type != (8, 10):
  185.                 break
  186.             while size > 0:
  187.                 s = self.fp.read(min(size, 8192))
  188.                 if not s:
  189.                     break
  190.                 o.write(s)
  191.                 size = size - len(s)
  192.         o.close()
  193.  
  194.         try:
  195.             try:
  196.                 # fast
  197.                 self.im = Image.core.open_ppm(outfile)
  198.             except:
  199.                 # slightly slower
  200.                 im = Image.open(outfile)
  201.                 im.load()
  202.                 self.im = im.im
  203.         finally:
  204.             try: os.unlink(outfile)
  205.             except: pass
  206.  
  207.  
  208. Image.register_open("IPTC", IptcImageFile)
  209.  
  210. Image.register_extension("IPTC", ".iim")
  211.  
  212. ##
  213. # Get IPTC information from TIFF, JPEG, or IPTC file.
  214. #
  215. # @param im An image containing IPTC data.
  216. # @return A dictionary containing IPTC information, or None if
  217. #     no IPTC information block was found.
  218.  
  219. def getiptcinfo(im):
  220.  
  221.     import TiffImagePlugin, JpegImagePlugin
  222.     import StringIO
  223.  
  224.     data = None
  225.  
  226.     if isinstance(im, IptcImageFile):
  227.         # return info dictionary right away
  228.         return im.info
  229.  
  230.     elif isinstance(im, JpegImagePlugin.JpegImageFile):
  231.         # extract the IPTC/NAA resource
  232.         try:
  233.             app = im.app["APP13"]
  234.             if app[:14] == "Photoshop 3.0\x00":
  235.                 app = app[14:]
  236.                 # parse the image resource block
  237.                 offset = 0
  238.                 while app[offset:offset+4] == "8BIM":
  239.                     offset = offset + 4
  240.                     # resource code
  241.                     code = JpegImagePlugin.i16(app, offset)
  242.                     offset = offset + 2
  243.                     # resource name (usually empty)
  244.                     name_len = ord(app[offset])
  245.                     name = app[offset+1:offset+1+name_len]
  246.                     offset = 1 + offset + name_len
  247.                     if offset & 1:
  248.                         offset = offset + 1
  249.                     # resource data block
  250.                     size = JpegImagePlugin.i32(app, offset)
  251.                     offset = offset + 4
  252.                     if code == 0x0404:
  253.                         # 0x0404 contains IPTC/NAA data
  254.                         data = app[offset:offset+size]
  255.                         break
  256.                     offset = offset + size
  257.                     if offset & 1:
  258.                         offset = offset + 1
  259.         except (AttributeError, KeyError):
  260.             pass
  261.  
  262.     elif isinstance(im, TiffImagePlugin.TiffImageFile):
  263.         # get raw data from the IPTC/NAA tag (PhotoShop tags the data
  264.         # as 4-byte integers, so we cannot use the get method...)
  265.         try:
  266.             type, data = im.tag.tagdata[TiffImagePlugin.IPTC_NAA_CHUNK]
  267.         except (AttributeError, KeyError):
  268.             pass
  269.  
  270.     if data is None:
  271.         return None # no properties
  272.  
  273.     # create an IptcImagePlugin object without initializing it
  274.     class FakeImage:
  275.         pass
  276.     im = FakeImage()
  277.     im.__class__ = IptcImageFile
  278.  
  279.     # parse the IPTC information chunk
  280.     im.info = {}
  281.     im.fp = StringIO.StringIO(data)
  282.  
  283.     try:
  284.         im._open()
  285.     except (IndexError, KeyError):
  286.         pass # expected failure
  287.  
  288.     return im.info
  289.